#include <vector>
#include <iostream>

#include "dexel.hpp"

uni_dexel::uni_dexel(double a,double b)
{
  v.clear();
  v.push_back(a);
  v.push_back(b);
}


int uni_dexel::solids() const
{
  return v.size()/2;
}

double uni_dexel::solid_begin(int i) const
{
  return v[i*2];
}

double uni_dexel::solid_end(int i) const
{
  return v[i*2+1];
}

bool uni_dexel::check() const
{ if(v.size()==0)
    return true;
    
  if(v.size()%2!=0)
    return false;
  for (unsigned int i=0; i<v.size()-1; i++)
    if(v[i]>v[i+1])
      return false;
    return true;
}

void uni_dexel::substract(double begin, double end)
{
  vector<double> nv;
  if(begin==end) return;
  
  for(int i=0; i<solids(); i++)
    {
      double
	a1=solid_begin(i),
	a2=solid_end(i);

      if(a1 < begin || a1 > end)
	nv.push_back(a1);
      
      if(begin>=a1 && begin<=a2)
	nv.push_back(begin);
      
      if(end>=a1 && end<=a2)
	nv.push_back(end);
      
      if(a2 < begin || a2 > end)
	nv.push_back(a2);
      
    }
  v=nv;
  
}

void  uni_dexel::substract(const interval &i){substract(i.b,i.e);}

void uni_dexel::substract(const dexel &d)
{
  for(int i=0; i<d.solids(); i++)
    substract(d.solid_begin(i),d.solid_end(i));
}


body_state uni_dexel::state(double x) const
{
  for(int i=0; i<solids(); i++)
    if(x>solid_begin(i) && x<solid_end(i))
      return SOLID;
  return AIR;
}

double uni_dexel::min() const
{
  if(solids()>=1)
    return solid_begin(0);
  else return 0;
}

double uni_dexel::max() const
{
  if(solids()>=1)
    return solid_end(solids()-1);
  else return 0;
}
 
void uni_dexel::get_values(vector<double> *vals) const
{
  *vals=v;
}

void uni_dexel::get_intervals(vector<interval> *ints) const
{
  ints->clear();
  for(int i=0; i<solids(); i++)
    ints->push_back(interval(solid_begin(i),solid_end(i)));
  
}
const uni_dexel& uni_dexel::operator= (const dexel& d)
{
  d.get_values(&v);
  return *this;
}

double uni_dexel::border(double z0, double z1) const
{
  if(state(z0)==state(z1))
    return 0;
  
  for(int i=0; i<solids(); i++)
    {
      double
	a1=solid_begin(i),
	a2=solid_end(i);
      if( (a1>z0 && a1<z1) ||
	  (a1>z1 && a1<z0))
	return a1;
      if( (a2>z0 && a2<z1) ||
	  (a2>z1 && a2<z0))
	return a2;
    }
  return 0;
}


///////////////////////////////////////////


inter_dexel::inter_dexel(double b,double e)
{
  ints.push_back(interval(b,e));
  
}

const inter_dexel& inter_dexel::operator= (const dexel& d)
{
  d.get_intervals(&ints);
  return *this;
}

int inter_dexel::solids() const
{
  return ints.size();
}

double inter_dexel::solid_begin(int i) const
{
  throw; //return ints[i].b;
}

  
double inter_dexel::solid_end(int i) const
{
  throw;//return ints[i].e;
}

double inter_dexel::min() const
{
  return ints.front().b;
}

double inter_dexel::max() const
{
  return ints.back().e;
}

  
body_state inter_dexel::state(double v) const
{
  body_state st=AIR;
    if(ints.size()==0) return AIR;
  
  c_iter e=ints.end();
  for(c_iter p=ints.begin();
      p!=e;
      ++p)
    if(p->state(v)==SOLID)
      st=SOLID;
  
  return st;
}


void inter_dexel::substract(double beg, double end)
{
  if(beg==end) return;
  
  // if(beg<=min() && end>=max())
//     ints.clear();
  
  iter e=ints.end();
  iter p=ints.begin();
  while(p!=e)
    {
      interval &v=*p;
      if(beg<=v.b && end>=v.e)
	{
	  p=ints.erase(p);
	  continue;
	}
      if(v.state(beg)==SOLID && v.state(end)==AIR)
	v.e=beg;
      if(v.state(beg)==AIR && v.state(end)==SOLID)
	v.b=end;
      if(v.state(beg)==SOLID && v.state(end)==SOLID)
	{
	  ints.insert(p,interval(v.b,beg));
	  v.b=end;
	  break;
	}
      ++p;
      
    }
}

void  inter_dexel::substract(const interval &i){substract(i.b,i.e);}

void inter_dexel::get_values(vector<double> *vals) const{
  vals->clear();
  c_iter e=ints.end();
  for(c_iter p=ints.begin();
      p!=e;
      ++p)
    {
      vals->push_back(p->b);
      vals->push_back(p->e);
    }
  
}
  
void inter_dexel::get_intervals(list<interval> *_ints) const{
  (*_ints)=ints;
}

      
double inter_dexel::border(double z0, double z1) const
{
  c_iter e=ints.end();
  for(c_iter p=ints.begin();
      p!=e;
      ++p)
    {
      double
	a1=p->b,
      	a2=p->e;
      if( (a1>z0 && a1<z1) ||
	  (a1>z1 && a1<z0))
	return a1;
      if( (a2>z0 && a2<z1) ||
	  (a2>z1 && a2<z0))
	return a2;
    }
  return 0;
}

      
	
  
